package PangController;

import PangModel.*;

import java.awt.*;
import java.util.ArrayList;

import static PangModel.Item.*;

/**
 * Created by baraaorabi on 4/23/15.
 */

public class CollisionManager {

    boolean pause = false;
    int gameBoundaryX;
    int gameBoundaryY;
    GameEngine gameEngine;

    public CollisionManager (){

    }
    public CollisionManager (GameEngine gameEngine){
        this.gameEngine = gameEngine;
    }

    public CollisionManager (int gameBoundaryX, int gameBoundaryY){
        this.gameBoundaryX = gameBoundaryX;
        this.gameBoundaryY = gameBoundaryY;
    }

    public boolean checkCollisions(ArrayList<ArrayList> gameObjects)  throws HeroDiedException{
        ArrayList<Hero> heroes = gameObjects.get(GameMap.HERO_INDEX);
        ArrayList<Ball> balls = gameObjects.get(GameMap.BALL_INDEX);;
        ArrayList<Animal> animals = gameObjects.get(GameMap.ANIMAL_INDEX);
        ArrayList<Bullet> bullets = gameObjects.get(GameMap.BULLET_INDEX);
        ArrayList<Barrier> barriers = gameObjects.get(GameMap.BARRIER_INDEX);
        ArrayList<Item> items = gameObjects.get(GameMap.ITEM_INDEX);
        ArrayList<Weapon> weapons = gameObjects.get(GameMap.WEAPON_INDEX);

        for (ArrayList<GameObject> al: gameObjects)
            for (GameObject go: al)
                go.move();

        if (balls.isEmpty()){
            gameEngine.notifyWin();
        }



        //Check Bullets against Balls, then Barriers, then Boundaries, then Animals
        checkBulletsCollisions(bullets, balls, barriers, animals, items);

        //Check Heroes collisions against Balls then against Animals, then Items
        checkHeroesCollisions(heroes, balls, animals, items, weapons);

        //Check Barrier Hitting Hero, then Ball, then Animal, then item
        checkBarrierCollisions(barriers, heroes, balls, animals, items);

        return true;
    }

    //collision checkers
    private void checkBulletsCollisions(ArrayList<Bullet> bullets, ArrayList<Ball> balls, ArrayList<Barrier> barriers, ArrayList<Animal> animals, ArrayList<Item> items) {

        for (int i = 0; i < bullets.size(); i++){
            boolean bulletDeleted = false;

            Bullet bullet = bullets.get(i);
            //bullet.move();
            //checking for bullet hitting ball
            for (int j = 0; j < balls.size(); j++){
                Ball ball = balls.get(j);
                //ball.move();
                if (bullet.includes(ball))    {
                    bulletHitsBall(bullet,ball, bullets, balls, i, j, items);
                    bulletDeleted= true;
                    break;
                }

            }

            if (bulletDeleted)
                continue;

            //checking for bullet hitting barrier
            for (int j = 0; j < barriers.size(); j++){
                Barrier barrier = barriers.get(j);

                if (barrier.includes(bullet) && bullets.indexOf(bullet) != -1)    {
                    bulletHitsBarrier(bullet, barrier, bullets, barriers, i, j);
                    bulletDeleted= true;
                    break;
                }

            }
            if (bulletDeleted)
                continue;


            //checking for bullet hitting animal
            for (int j = 0; j < animals.size(); j++){
                Animal animal = animals.get(j);
               // animal.move();
                if (bullet.includes(animal))    {
                    bulletHitsAnimal(bullet, animal, bullets, animals, i, j);
                    bulletDeleted= true;
                    break;
                }

            }
            if (bulletDeleted)
                continue;



            // checking for out of bound

        }
    }

    private void checkHeroesCollisions(ArrayList<Hero> heroes, ArrayList<Ball> balls, ArrayList<Animal> animals, ArrayList<Item> items, ArrayList<Weapon> weapons) throws HeroDiedException {
        for (int i = 0; i < heroes.size(); i++){
            Hero hero = heroes.get(i);

            //against Balls
            for (int j = 0; j < balls.size(); j++){
                Ball ball = balls.get(j);

                if (hero.includes(ball))    {
                    heroHitsBall(hero, ball, heroes, balls, i, j);

                }

            }

            //against Animals
            for (int j = 0; j < animals.size(); j++){
                Animal animal = animals.get(j);

                if (hero.includes(animal))    {
                    heroHitsAnimal(hero, animal, heroes, animals, i, j);
                }

            }

            //against Items
            for (int j = 0; j< items.size(); j++){
                Item item = items.get(j);

                if (hero.includes(item))    {
                    try {
                        heroHitsItem(hero, item, heroes, items, i, j, weapons);
                    } catch (UnsupportedArgumentException e) {
                        e.printStackTrace();
                    }
                    j--;
                    //i--;
                }

            }

            // checking for out of bound

        }
    }

    public void checkBarrierCollisions(ArrayList<Barrier> barriers, ArrayList<Hero> heroes, ArrayList<Ball> balls, ArrayList<Animal> animals, ArrayList<Item> items) {
        for (int i = 0; i < barriers.size(); i++){
            Barrier barrier = barriers.get(i);

            //against Hero
            for (int j = 0; j < heroes.size(); j++){
                Hero hero = heroes.get(j);

                if (barrier.includes(hero))    {
                    barrierHitsHero(barrier, hero, barriers, heroes, i, j);
                }

            }

            //against Balls
            for (int j = 0; j < balls.size(); j++){
                Ball ball = balls.get(j);

                if (barrier.includes(ball))    {
                    barrierHitsBall(barrier, ball, barriers, balls, i, j);
                }

            }

            //against Animals
            for (int j = 0; j < animals.size(); j++){
                Animal animal = animals.get(j);

                if (barrier.includes(animal))    {
                    barrierHitsAnimal(barrier, animal, barriers, animals, i, j);
                }

            }

            //against Items
            for (int j = 0; j < items.size(); j++){
                Item item = items.get(j);
                //item.move();
                if (barrier.includes(item))    {
                    barrierHitsItem(barrier, item, barriers, items, i, j);
                } else {
                    item.resetDirection();
                }

            }


        }
    }

    //bullet hits actions
    private void bulletHitsAnimal(Bullet bullet, Animal animal, ArrayList<Bullet> bullets, ArrayList<Animal> animals, int i, int j) {
        incrementScore(Animal.SCORE);
        bullets.remove(i);
        animals.remove(j);

    }

    private void bulletHitsBall(Bullet bullet, Ball ball, ArrayList<Bullet> bullets, ArrayList<Ball> balls, int i, int j, ArrayList<Item> items){
        incrementScore(Ball.SCORE * ball.getSize());
        bullets.remove(i);
        balls.remove(j);

        /*if (ball.getSize() > 1){
            Ball left = new Ball(ball.getSize()-1, ball.getDirection something );
            Ball right = new Ball(ball.getSize()-1, ball.getDirection something );
            balls.add(left);
            balls.add(right);
        }
        balls.remove(j);*/

        ArrayList<ArrayList> container  = ball.split();
        items.addAll(container.get(ball.BALL_ITEM_INDEX));
        balls.addAll(container.get(ball.BALL_BALL_INDEX));

    }

    private boolean bulletHitsBarrier(Bullet bullet, Barrier barrier, ArrayList<Bullet> bullets, ArrayList<Barrier> barriers, int i, int j){
        bullets.remove(i);

        if (barrier.isDestructible())
            if (barrier.getRoughness() > 1){
                barrier.decrementRoughness();

            }
            else {
                incrementScore(barrier.SCORE);
                barriers.remove(i);


            }
        //Maybe needs checking if it is sticky rope
        else
            return false;
        return true;
    }

    //hero hits actions
    private void heroHitsBall(Hero hero, Ball ball, ArrayList<Hero> heros, ArrayList<Ball> balls, int i, int j) throws HeroDiedException{
        if (!hero.hit())
            throw new HeroDiedException();
    }

    private void heroHitsItem(Hero hero, Item item, ArrayList<Hero> heroes, ArrayList<Item> items, int i, int j, ArrayList<Weapon> weapons) throws UnsupportedArgumentException {
        // dear baraa
        // first check the item type, for example
        // if (item,getType == Item,ITEM_BONUS_SCORE)
        //     increment the score
        // else if (item.getType == Item.POWERUP_MACHINE_GUN)
        //      then replace the weapon in the arraylist with the machine gun
        //
        //  also if it is a immunity powerup, then send it to the hero, by the addItem method of the hero
        //  Cheers
        switch (item.getItemType()){
            case POWERUP_IMMUNITY :
                hero.addItem(item);
                break;
            case POWERUP_MACHINE_GUN :
                weapons.remove(0);
                weapons.add(new MachineGun());
                break;
            case POWERUP_STICKY_ROPE :
                weapons.remove(0);
                weapons.add(new StickyHook());
                break;
            case ITEM_BONUS_SCORE :
                gameEngine.incrementScore(ITEM_BONUS_SCORE);
                break;
            case ITEM_BONUS_TIME :
                gameEngine.incrementTime(ITEM_BONUS_TIME);

        }

        items.remove(j);
    }

    private void heroHitsAnimal(Hero hero, Animal animal, ArrayList<Hero> heroes, ArrayList<Animal> animals, int i, int j) throws HeroDiedException{
        if (!hero.hit())
            throw new HeroDiedException();
    }

    //barrier hits actions
    private void barrierHitsItem(Barrier barrier, Item item, ArrayList<Barrier> barriers, ArrayList<Item> items, int i, int j) {
        item.setDirection(0,0);
    }

    private void barrierHitsAnimal(Barrier barrier, Animal animal, ArrayList<Barrier> barriers, ArrayList<Animal> animals, int i, int j) {
        switch (animal.getAnimalType()) {
            case Animal.ANIMAL_PHOENIX :
                break;
            case Animal.ANIMAL_SNAIL:
                animal.bounce(GameObject.X);
                break;
        }
    }

    private void barrierHitsBall(Barrier barrier, Ball ball, ArrayList<Barrier> barriers, ArrayList<Ball> balls, int i, int j) {
        double x = barrier.getCoordinates().getX();
        double ballCenter = ball.getCoordinates().getX() + ball.getWidth()/2;

        if (ballCenter > x && ballCenter < x + barrier.getWidth())
            ball.bounce(GameObject.Y); //change to ball.bounce()
        else
            ball.bounce(GameObject.X);
    }

    private void barrierHitsHero(Barrier barrier, Hero hero, ArrayList<Barrier> barriers, ArrayList<Hero> heroes, int i, int j) {

    }

    //others
    private void incrementScore(int score){
        gameEngine.incrementScore(score);
    }


}
